package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.dictionarydata.DictionaryCodeData;
import com.jinmdz.fmis.api.admin.model.dictionarydata.DictionaryDataSaveData;
import com.jinmdz.fmis.api.admin.model.dictionarydata.DictionaryListItem;
import com.jinmdz.fmis.api.api.model.common.IdData;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.common.util.third.Pinyin4jUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.EDictCode;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.DictionaryDataDao;
import com.jinmdz.fmis.dao.admin.model.dictionarydata.DictionaryDataEditItem;
import com.jinmdz.fmis.dao.admin.model.dictionarydata.DictionaryDataListItem;
import com.jinmdz.fmis.mapper.entity.DataDictionaryEntity;
import com.jinmdz.fmis.mapper.mapper.DataDictionaryMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;

/**
 * 字典项目维护
 *
 * @author GuanKui
 * @date 2020/3/11 13:11
 */
@Service("dictionaryDataService")
public class DictionaryDataService extends BaseService {

    @Resource
    private DictionaryDataDao dictionaryDataDao;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private DataDictionaryMapper dataDictionaryMapper;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    /**
     * 加载字典类型信息列表
     *
     * @param
     * @return
     * @author GuanKui
     * @date 2020/3/11  13:13
     */
    public BaseResult<ArrayList<DictionaryListItem>> loadDictionaryList() {
        ArrayList<DictionaryListItem> loadItems = new ArrayList<>();
        for (EDictCode codeEnum : EDictCode.values()) {
            // 屏蔽空枚举以及子枚举
            if (codeEnum == EDictCode.EMPTY || codeEnum == EDictCode.SEX_SIMPLE) {
                continue;
            }
            DictionaryListItem loadItem = new DictionaryListItem();
            loadItem.setDictCode(codeEnum.getCode())
                    .setDictText(codeEnum.getMessage());
            loadItems.add(loadItem);
        }
        return successList(loadItems);
    }

    /**
     * 根据字典编码加载字典下的数据项列表
     *
     * @param data 字典请求数据
     * @return
     * @author GuanKui
     * @date 2020/3/11  14:30
     */
    public BaseResult<ArrayList<DictionaryDataListItem>> loadDictionaryDataListWithCode(DictionaryCodeData data) {
        ArrayList<DictionaryDataListItem> loadItems = dictionaryDataDao.listDictionaryDataListByCode(data.getDictCode());
        return successList(loadItems);
    }

    /**
     * 根据字典数据项目id，加载字典数据项基本信息
     *
     * @param data 请求数据
     * @return
     * @author GuanKui
     * @date 2020/3/11  15:04
     */
    public BaseResult<DictionaryDataSaveData> loadDictionaryDataWithId(IdData data) {
        DictionaryDataEditItem loadItem = dictionaryDataDao.getDictionaryDataEditById(data.getId());
        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("主键错误，不存在此字典信息");
        }

        DictionaryDataSaveData loadData = BeanUtil.copy2Bean(loadItem, new DictionaryDataSaveData());
        return successData(loadData);
    }

    /**
     * 保存字典数据基本信息
     *
     * @param userItem 当前账号
     * @param data     保存数据
     * @return
     * @author GuanKui
     * @date 2020/3/11  16:24
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveDictionaryData(UserItem userItem, DictionaryDataSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateDictionaryData(userItem, data);
        } else {
            id = insertDictionaryData(userItem, data);
        }

        // 刷新缓存数据
        dictionaryWrapper.refreshDictionary();

        return success("保存成功");
    }

    /**
     * 插入数据字典信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author GuanKui
     * @date 2020/3/11  16:24
     */
    private Integer insertDictionaryData(UserItem userItem, DictionaryDataSaveData data) throws ActionException {
        // 创建实体
        DataDictionaryEntity entity = getEntity(userItem, DataDictionaryEntity.class);

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对数据字典进行判断处理
        checkDictionaryDataValue(entity);

        // 新增数据字典信息
        dataDictionaryMapper.insertDataDictionary(entity);
        // 判断保存数据字典结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存字典信息失败");
        }

        // 添加操作日志
        saveDictionaryDataLog(userItem, operationLogCode.getInsert(), data, null, entity);
        return entity.getId();
    }

    /**
     * 验证处理数据字典
     *
     * @param entity 字典信息
     * @return
     * @author GuanKui
     * @date 2020/3/11  16:24
     */
    private void checkDictionaryDataValue(DataDictionaryEntity entity) throws ActionException {
        // 判断禁用状态
        if (DataUtil.isNull(entity.getDisableState())) {
            entity.setDisableState(0);
        }

        // 判断排序值
        if (DataUtil.isNull(entity.getSort())) {
            entity.setSort(0);
        }

        // 判断预留值
        if (DataUtil.isNull(entity.getDataValue())) {
            entity.setDataValue(BigDecimal.valueOf(entity.getDataCode()));
        }

        // 判断是否可修改
        if (DataUtil.valid(entity.getUnmodified())) {
            throw exception("数据不可修改");
        }

        // 判断字典编码的重复性
        Integer dictionaryDataCodeId = dictionaryDataDao.getDictionaryIdByDataCode(entity.getId(), entity.getDictCode(), entity.getDataCode());
        if (DataUtil.valid(dictionaryDataCodeId)) {
            throw exception("存在重复的字典数据编码");
        }

        // 判断字典数据文本值的重复性
        Integer dictionaryDataTextId = dictionaryDataDao.getDictionaryIdByDataText(entity.getId(), entity.getDictCode(), entity.getDataText());
        if (DataUtil.valid(dictionaryDataTextId)) {
            throw exception("存在重复的字典数据编码");
        }

        // 判断数据文本默认值
        if (DataUtil.valid(entity.getAsDefault())) {
            Integer dictionaryDefaultId = dictionaryDataDao.getDictionaryIdAsDefault(entity.getId(), entity.getDictCode());
            if (DataUtil.valid(dictionaryDefaultId)) {
                throw exception("存在已默认的字典数据");
            }
        }

        // 重新设置设置简拼
        entity.setDataTextAbbr(Pinyin4jUtil.getPinyinAbbrToLowerCase(entity.getDataText()));
    }

    /**
     * 添加接运修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author GuanKui
     * @date 2020/3/13  16:43
     */
    private void saveDictionaryDataLog(UserItem userItem, Integer logTypeCode, DictionaryDataSaveData data, String oldValue, DataDictionaryEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存字典数据基本信息，字典编码[{0}]，数据编码[{1}]，字典数据文本值[{2}]，默认值[{3}]，禁用状态[{4}]，备注信息[{5}]，操作人员[{6}]"
                , data.getDictCode(), String.valueOf(data.getDataCode())
                , data.getDataText(), DataUtil.valid(data.getAsDefault()) ? "是" : "否"
                , DataUtil.valid(data.getDisableState()) ? "禁用" : "有效"
                , data.getRemark(), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新数据字典信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-10 11:40
     */
    private void updateDictionaryData(UserItem userItem, DictionaryDataSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求字典主键与字典版本号不能为空");
        }

        // 通过主键获取数据字典信息
        DataDictionaryEntity entity = dataDictionaryMapper.getDataDictionaryById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("字典主键错误，不存在此数据字典");
        }

        // 验证信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("数据字典"));
        }

        // 判断编码是否更改
        if (!DataUtil.equals(data.getDataCode(), entity.getDataCode())) {
            throw exception("数据编码发生了改变，无法保存");
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);
        // 记录原编码
        Integer dataCode = entity.getDataCode();

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 对数据字典进行判断处理
        checkDictionaryDataValue(entity);

        // 设置原编码，编辑时编码不做修改
        entity.setDataCode(dataCode);

        // 更新数据字典信息
        dataDictionaryMapper.updateDataDictionary(entity);

        // 添加操作日志
        saveDictionaryDataLog(userItem, operationLogCode.getUpdate(), data, oldValue, entity);
    }

    /**
     * 删除字典数据项基本信息
     *
     * @param userItem 当前账号
     * @param data     字典数据
     * @return
     * @author GuanKui
     * @date 2020/3/11  15:10
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteDictionaryDataWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {

        // 不存在可删除数据
        if (DataUtil.invalid(data)) {
            return failure("不存在要删除的字典信息");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("字典主键存在重复");
        }

        // 记录字典信息集合
        ArrayList<DictionaryDataEditItem> loadItems = new ArrayList<>();

        // 进行遍历删除信息
        for (IdVersionData idData : data) {
            // 通过主键查询字典信息
            DictionaryDataEditItem loadItem = dictionaryDataDao.getDictionaryDataEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在此字典信息");
            }

            // 验证字典信息版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("字典信息"));
            }

            // 判断是否可修改
            if (DataUtil.valid(loadItem.getUnmodified())) {
                throw exception("存在不可修改字典");
            }

            // 删除字典信息
            dataDictionaryMapper.deletedForDataDictionary(loadItem.getId(), userItem.getId(), loadItem.getVersion());
            // 记录字典信息
            loadItems.add(loadItem);
        }

        // 刷新缓存数据
        dictionaryWrapper.refreshDictionary();

        // 添加日志
        deleteDictionaryDataLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author GuanKui
     * @date 2020/3/13  16:15
     */
    private void deleteDictionaryDataLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<DictionaryDataEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除字典数据信息，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }
}